#include "xudp.h"

static xudp_t udp_socket[XUDP_CFG_MAX_UDP]; // UDP连接块

xudp_t *xudp_open(xudp_handler_t handler)
{
    // 给hander这个函数分配一个udp控制块
    xudp_t *udp, *end;

    for (udp = udp_socket, end = &udp_socket[XUDP_CFG_MAX_UDP]; udp < end; udp++)
    {
        if (udp->state == XUPD_STATE_FREE)
        {
            udp->state = XUDP_STATE_USED;
            udp->local_port = 0;
            udp->udp_handler = handler;
            return udp;
        }
    }

    return (xudp_t *)0; // 没有空闲位置了
};

void xudp_close(xudp_t *udp)
{
    udp->state = XUPD_STATE_FREE;
};

xudp_t *xudp_find(uint16_t port)
{
    // 找到端口号对应的udp
    xudp_t *udp, *end;

    for (udp = udp_socket, end = &udp_socket[XUDP_CFG_MAX_UDP]; udp < end; udp++)
    {
        if (udp->state == XUDP_STATE_USED && udp->local_port == port)
        {
            return udp;
        }
    }

    return (xudp_t *)0; // 没有空闲位置了
};

xnet_err_t xudp_bind(xudp_t *udp, uint16_t local_port)
{
    // 绑定为udp绑定端口
    if (local_port == 0)
    {
        return XNET_ERR_PARAM;
    }
    xudp_t *find_result = xudp_find(local_port);

    if (find_result != (xudp_t *)0)
    {
        return XNET_ERR_BINDED; // 已经被绑定了
    }
    else
    {
        udp->local_port = local_port;
    }
};

void xudp_init()
{
    // 初始化空间
    memset(udp_socket, 0, sizeof(udp_socket));
};
void xudp_in(xudp_t *udp, xipaddr_t *src_ip, xnet_packet_t *packet)
{
    xudp_hdr_t *udp_hdr = (xudp_hdr_t *)packet->data;
    uint16_t hdr_size = swap_order16(udp_hdr->total_len);

    if (packet->size < sizeof(xudp_hdr_t) || packet->size < hdr_size)
    {
        // 包损坏
        return;
    }

    uint16_t pre_checksum = udp_hdr->checksum;
    udp_hdr->checksum = 0;

    if (pre_checksum != 0)
    {
        // 等于0的时候选择不校验
        uint16_t checksum = checksum_peso(src_ip, &my_ip, XNET_PROTOCOL_UDP,
                                          (uint16_t *)udp_hdr, swap_order16(udp_hdr->total_len));
        if (checksum == 0)
        {
            checksum = 0xffff;
        }
        if (checksum != pre_checksum)
        {
            if (NEED_UDP_GDB)
            {
                print_info("udp receive a wrong checksum packet");
            }
            // 校验和不对
            return;
        }
    }

    uint16_t src_port = swap_order16(udp_hdr->src_port);
    remove_header(packet, sizeof(xudp_hdr_t));
    if (NEED_UDP_GDB)
    {
        print_info("get a udp packet from port %d to port %d", swap_order16(udp_hdr->src_port), swap_order16(udp_hdr->dest_port));
    }
    if (udp)
    {
        // 交给对应的回调函数处理
        udp->udp_handler(udp, src_ip, src_port, packet);
    }
};
xnet_err_t xudp_out(xudp_t *udp, xipaddr_t *dest_ip, uint16_t dest_port, xnet_packet_t *packet){
    add_header(packet,sizeof(xudp_hdr_t));
    xudp_hdr_t * udp_hdr=packet->data;
    udp_hdr->dest_port=swap_order16(dest_port);
    udp_hdr->src_port=swap_order16(udp->local_port);
    udp_hdr->checksum=0;
    udp_hdr->total_len=swap_order16(packet->size);
    udp_hdr->checksum= checksum_peso(&my_ip,dest_ip , XNET_PROTOCOL_UDP,
                                          (uint16_t *)packet->data, swap_order16(udp_hdr->total_len));
    

    if (NEED_UDP_GDB)
    {
        print_info("try to send a udp packet from port %d to port %d", swap_order16(udp_hdr->src_port), swap_order16(udp_hdr->dest_port));
    }
    return xip_out(XNET_PROTOCOL_UDP,dest_ip,packet);
};